<?php

namespace App\Http\Controllers;

use App\Http\Requests\TradeRequest;
use App\Http\Resources\RecordCollection;
use App\Http\Resources\TradingCollection;
use App\Jobs\MatchTrading;
use App\Model\Account;
use App\Model\Chart;
use App\Model\Coin;
use App\Model\Reward;
use App\Model\Trade;
use App\Model\TradeLog;
use App\Model\User;
use App\Traits\Password;
use App\Traits\TradeQueue;
use Cache;
use Carbon\Carbon;
use DB;
use Exception;
use Illuminate\Http\Request;

class TradeController extends Controller
{
    use Password, TradeQueue;

    /**
     * 首页币种成交量、成交额
     *
     * @param $type
     * @return \Illuminate\Http\JsonResponse
     */
    public function coins($type)
    {
        if ($type == 'cny') { // 人民币交易
            $coins = Coin::select(['id', 'pay_coin_id', 'name', 'image', 'title'])
                ->where('status', 1)
                ->where('pay_coin_id', 0)
                ->get();
        } else { // 币币交易
            $coins = Coin::select(['id', 'pay_coin_id', 'name', 'image', 'title'])
                ->where('status', 1)
                ->where('pay_coin_id', '!=', 0)
                ->get();
        }

        foreach ($coins as $coin) {
            $aDayAgo = Carbon::now()->subDay();
            // 24 小时成交量
            $coin->number = TradeLog::where('coin_id', $coin->id)
                ->where('created_at', '>', $aDayAgo)
                ->sum('number') ?: 0;
            // 24 小时成交额
            $coin->money = TradeLog::where('coin_id', $coin->id)
                ->select(DB::raw('sum(number * price) as money'))
                ->where('created_at', '>', $aDayAgo)
                ->value('money') ?: 0;
        }

        return response()->json($coins);
    }

    /**
     * 交易页面 当前价、最高价、最低价、成交额、成交量
     *
     * @param $coinId
     * @return \Illuminate\Http\JsonResponse
     */
    public function info($coinId)
    {
        if (! Coin::find($coinId)) {
            return response()->json(['message' => 'Not Found.'], 404);
        }

        $aDayAgo = Carbon::now()->subDay();

        // 当前价
        $now = TradeLog::where('coin_id', $coinId)
            ->orderBy('id', 'desc')
            ->value('price');
        // 最高价
        $max = TradeLog::where('coin_id', $coinId)
            ->where('created_at', '>', $aDayAgo)
            ->max('price');
        // 最低价
        $min = TradeLog::where('coin_id', $coinId)
            ->where('created_at', '>', $aDayAgo)
            ->min('price');
        // 成交额
        $money = TradeLog::select(DB::raw('sum(price*number) as money'))
            ->where('coin_id', $coinId)
            ->where('created_at', '>', $aDayAgo)
            ->value('money');
        // 成交量
        $number = TradeLog::where('coin_id', $coinId)
            ->where('created_at', '>', $aDayAgo)
            ->sum('number');

        $price = compact('now', 'max', 'min');

        return response()->json(compact('price', 'money', 'number'));
    }

    /**
     * 委托中的交易
     *
     * @param $coinId
     * @return \Illuminate\Http\JsonResponse
     */
    public function trading($coinId)
    {
        if (! Coin::find($coinId)) {
            return response()->json(['message' => 'Not Found.'], 404);
        }

        $buy  = Trade::select(['price', DB::raw('sum(number - deal) as number')])
            ->where('coin_id', $coinId)
            ->where('status', 0)
            ->where('type', 0)
            ->groupBy('price')
            ->orderBy('price', 'desc')
            ->take(5)
            ->get();
        $sell = Trade::select(['price', DB::raw('sum(number - deal) as number')])
            ->where('coin_id', $coinId)
            ->where('status', 0)
            ->where('type', 1)
            ->groupBy('price')
            ->orderBy('price', 'asc')
            ->take(5)
            ->get();

        return response()->json(compact('buy', 'sell'));
    }

    /**
     * 交易
     *
     * @param TradeRequest $request
     * @param Coin         $coin
     * @return \Illuminate\Http\JsonResponse
     */
    public function trade(TradeRequest $request, Coin $coin)
    {
        $price  = $request->input('price');
        $number = $request->input('number');

        if ($price <= 0 || $number <= 0) {
            return response()->json(['error' => '交易价格或数量错误'], 403);
        }

        $user = request()->user();

        // 判断交易密码
        $this->checkPayPassword($user, $request->input('pay_password'));

        // 数量限制
        if ($number < $coin->min) {
            return response()->json(['error' => '数量不得低于最小交易量' . $coin->min], 403);
        }
        // 价格限制
        // 昨日最后一笔交易价格
        $lastTrade = TradeLog::where('created_at', '<', Carbon::today())->orderBy('id', 'desc')->first();
        if ($lastTrade) {
            $down = $coin->down <= 100 ? $coin->down : 100;
            if ($price < $lastTrade->price * (1 - $down / 100) || $price > $lastTrade->price * (1 + $coin->up / 100)) {
                return response()->json(['error' => '价格不得超出最大涨跌价范围'], 403);
            }
        }

        // 人民币帐户
        $rmbAccount = Account::where('user_id', $user->id)->where('coin_id', 0)->first();
        // 虚拟币帐户
        $coinAccount = Account::where('user_id', $user->id)->where('coin_id', $coin->id)->first();

        if ($request->input('trade_type') == 0) { // 买入
            // 买入所需人民币
            $money = $number * $price * (1 + $coin->buy_fee / 100);
            if ($rmbAccount->available < $money) {
                return response()->json(['error' => '可用余额不足'], 403);
            }
            $trade          = new Trade();
            $trade->user_id = $user->id;
            $trade->coin_id = $coin->id;
            $trade->type    = 0;
            $trade->price   = $price;
            $trade->number  = $number;

            try {
                DB::transaction(function () use ($trade, $money, $rmbAccount) {
                    $trade->save();
                    // 账户可用人民币减少，不可用增加
                    $rmbAccount->disable($money);
                });
            } catch (Exception $exception) {
                return response()->json(['error' => '网络异常，请重试'], 500);
            }
            $this->addBuy($trade);
            $this->dispatch(new MatchTrading($trade));

            return response()->json(['message' => '挂单成功'], 200);
        } else { // 卖出
            if ($coinAccount->available < $number) {
                return response()->json(['error' => '可用虚拟币不足'], 403);
            }

            $trade          = new Trade();
            $trade->user_id = $user->id;
            $trade->coin_id = $coin->id;
            $trade->type    = 1;
            $trade->price   = $price;
            $trade->number  = $number;
            try {
                DB::transaction(function () use ($coinAccount, $number, $trade) {
                    $trade->save();
                    // 卖出 虚拟币可用减少，不可用增加
                    $coinAccount->disable($number);
                });
            } catch (Exception $exception) {
                return response()->json(['error' => '网络异常，请重试'], 500);
            }
            $this->addSell($trade);
            $this->dispatch(new MatchTrading($trade));

            return response()->json(['message' => '挂单成功'], 200);
        }
    }

    // 委托管理
    public function myTrading($coinId)
    {
        $trade = Trade::select(['id', 'type', 'price', 'number', 'deal'])
            ->where('user_id', request()->user()->id)
            ->where('coin_id', $coinId)
            ->where('status', 0)
            ->orderBy('created_at', 'desc')
            ->paginate();
        if (! $trade->total()) {
            return response()->json(['error' => '没有委托'], 404);
        }

        return new TradingCollection($trade);
    }

    //交易撤销

    /**
     * @param $tradeId
     * @return \Illuminate\Http\JsonResponse
     */
    public function cancel($tradeId)
    {
        // 取出要撤销订单
        $trade = Trade::where('id', $tradeId)->where('status', 0)->first();
        if (! $trade) {
            return response()->json(['error' => '订单不存在'], 404);
        }
        $coin = Coin::where('id', $trade->coin_id)->first();

        if ($trade->type == 0) { // 买入
            // 人民币账户
            $rmbAccount = Account::where('user_id', request()->user()->id)->where('coin_id', 0)->first();
            // 买入所需人民币
            $money = ($trade->number - $trade->deal) * $trade->price * (1 + $coin->buy_fee / 100);
            // 订单状态变更
            $trade->status = 2;
            try {
                DB::transaction(function () use ($trade, $rmbAccount, $money) {
                    $trade->save();
                    // 人民币账户可用增加，不可用减少
                    $rmbAccount->enable($money);
                });
            } catch (Exception $exception) {
                return response()->json(['error' => '网络异常，请重试'], 500);
            }
            $this->addBuy($trade);
            $this->dispatch(new MatchTrading($trade));

            return response()->json(['message' => '撤销成功'], 200);
        } else { // 卖出
            // 虚拟币账户
            $coinAccount = Account::where('user_id', request()->user()->id)->where('coin_id', $trade->coin_id)->first();
            // 未成交数量
            $undeal = $trade->number - $trade->deal;
            // 订单状态变更
            $trade->status = 2;

            try {
                DB::transaction(function () use ($trade, $coinAccount, $undeal) {
                    $trade->save();
                    // 虚拟币可用增加，不可用减少
                    $coinAccount->enable($undeal);
                });
            } catch (Exception $exception) {
                return response()->json(['error' => '网络异常，请重试'], 500);
            }
            $this->addSell($trade);
            $this->dispatch(new MatchTrading($trade));

            return response()->json(['message' => '撤销成功'], 200);
        }
    }

    /**
     * 用户成交记录
     *
     * @param $coinId
     * @param $type
     * @return RecordCollection|\Illuminate\Http\JsonResponse
     */
    public function record($coinId, $type)
    {
        // 按天数3天、一周、一个月、半年查找
        $timeArray = [3, 7, 30, 90, 180];
        if (! in_array($type, $timeArray)) {
            $time = Carbon::now()->subDays(3);
        } else {
            $time = Carbon::now()->subDays($type);
        }
        $record = Trade::select('id', 'type', 'created_at', 'price', 'number')
            ->where('coin_id', $coinId)
            ->where('user_id', request()->user()->id)
            ->where('created_at', '>', $time)
            ->where('status', 1)
            ->orderBy('created_at', 'desc')
            ->paginate();

        if (! $record->total()) {
            return response()->json(['error' => '没有成交记录'], 404);
        }

        return new RecordCollection($record);
    }

    /**
     * 邀请奖励
     *
     * @param $tradeLog
     * @return \Illuminate\Http\JsonResponse
     */
    protected function reward($tradeLog)
    {
        // 判断买家是否有邀请人pid
        $buyer = User::where('id', $tradeLog->buyer)->first();
        if ($buyer->pid != 0) {
            $reward          = new Reward();
            $reward->user_id = $buyer->pid;
            $reward->coin_id = $tradeLog->coin_id;
            $reward->fee     = $tradeLog->buy_fee;
            $reward->number  = $tradeLog->buy_fee * 0.3;
            $reward->type    = 0;
            $reward->status  = 0;
            if (! $reward->save()) {
                return response()->json(['error' => '网络异常，请重试'], 500);
            }
        }
        // 判断卖家是否有邀请人pid
        $seller = User::where('id', $tradeLog->seller)->first();
        if ($seller->pid != 0) {
            $reward          = new Reward();
            $reward->user_id = $seller->pid;
            $reward->coin_id = $tradeLog->coin_id;
            $reward->fee     = $tradeLog->sell_fee;
            $reward->number  = $tradeLog->sell_fee * 0.3;
            $reward->type    = 1;
            $reward->status  = 0;
            if (! $reward->save()) {
                return response()->json(['error' => '网络异常，请重试'], 500);
            }
        }

        return response()->json(['message' => 'ok'], 200);
    }

    /**
     * 深度图数据
     *
     * @param $coinId
     * @return \Illuminate\Http\JsonResponse
     */
    public function depth($coinId)
    {
        $coin = Coin::where('id', $coinId)->where('status', 1)->first();
        if (! $coin) {
            return response()->json(['error' => '币种错误'], 400);
        }
        // 同一买价累计量
        $buy = Trade::where('coin_id', $coinId)
            ->where('type', 0)
            ->where('status', 0)
            ->select('price', DB::raw('sum(number-deal) as number'))
            ->first();
        // 同一卖价累积量
        $sell = Trade::where('coin_id', $coinId)
            ->where('status', 0)
            ->where('type', 1)
            ->select('price', DB::raw('sum(number-deal) as number'))
            ->first();

        return response()->json(compact($buy, $sell));
    }

    public function chart(Request $request)
    {
        $this->validate($request, [
            'coin_id' => 'required|exists:coins,id',
            'type'    => 'required',
        ]);
        $time=[5, 15, 30, 60, 480, 1440];
        if(!in_array($request->input('type'),$time)){
            $type=5;
        }else{
            $type=$request->input('type');
        }
        if(Cache::has('charts'.$request->input('coin_id').$type)){
            return response()->json(Cache::get('charts'.$request->input('coin_id').$type));
        }
        $this->addChart($request->input('coin_id'));
        $charts=Chart::where('coin_id',$request->input('coin_id'))
            ->where('time_type',$type)
            ->select('data')
            ->where('id','desc')
            ->take(100)
            ->get()
            ->toArray();

    }
}